package com.cloudkinto.service.stock.impl;

import cn.afterturn.easypoi.entity.ImageEntity;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import com.baomidou.mybatisplus.core.assist.ISqlRunner;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.cloudkinto.common.DicBusinessConstant;
import com.cloudkinto.common.DicBusinessItemConstant;
import com.cloudkinto.common.common.DateFormater;
import com.cloudkinto.common.common.DateUtils;
import com.cloudkinto.common.constant.SysConstant;
import com.cloudkinto.common.exception.BizException;
import com.cloudkinto.common.utils.ExcelUtils;
import com.cloudkinto.common.utils.StringsUtil;
import com.cloudkinto.common.utils.TimeUtils;
import com.cloudkinto.common.utils.dict.StaticDict;
import com.cloudkinto.dao.*;
import com.cloudkinto.entity.*;
import com.cloudkinto.extentity.ProductStockDetailDto;
import com.cloudkinto.extentity.SerialNumberPageDto;
import com.cloudkinto.extentity.StockPickUpDto;
import com.cloudkinto.extentity.StockPickUpItem;
import com.cloudkinto.extentity.shelf.Item;
import com.cloudkinto.extentity.shelf.ShelfSortUpdateDto;
import com.cloudkinto.extentity.stock.PickupStockRackDto;
import com.cloudkinto.extentity.stock.StockPickUpDetailDto;
import com.cloudkinto.extentity.stock.StockPickUpSort;
import com.cloudkinto.service.dic.DicBusinessItemService;
import com.cloudkinto.service.fbaorderoutput.FbaOrderOutputService;
import com.cloudkinto.service.finance.vo.IdAndNameEntity;
import com.cloudkinto.service.orderoutput.vo.BatchPickUpRes;
import com.cloudkinto.service.orderoutput.vo.PositionAndNumberDTO;
import com.cloudkinto.service.product.ProductStockFlowingService;
import com.cloudkinto.service.product.vo.DealStockRackRes;
import com.cloudkinto.service.product.vo.rack.SendRes;
import com.cloudkinto.service.region.JpRegionService;
import com.cloudkinto.service.serialmanage.vo.SerialNumberExportVo;
import com.cloudkinto.service.stock.StockPickUpRuleService;
import com.cloudkinto.service.stock.StockPickUpService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.cloudkinto.common.web.PageResult;
import com.cloudkinto.common.web.SingleResult;

import com.cloudkinto.service.stock.vo.*;
import com.cloudkinto.service.stock.vo.pickuprule.PickupRuleReq;
import com.cloudkinto.service.stock.vo.pickuprule.PickupRuleRes;
import com.cloudkinto.service.storage.StorageService;
import com.cloudkinto.service.storage.StorageShelfService;
import com.cloudkinto.service.storage.vo.PickupPreviewRes;
import com.cloudkinto.utils.BarCodeUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Value;
import org.apache.commons.collections.BinaryHeap;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * service实现类
 * </p>
 *
 * @author zhujiale
 * @since 2022-12-23
 */
@Service
@Transactional(rollbackFor = Exception.class)//事务回滚
public class StockPickUpServiceImpl extends ServiceImpl<StockPickUpDao, StockPickUpDo> implements StockPickUpService {
    @Autowired
    private StockPickUpDao dao;
    @Autowired
    private StockPickUpDetailDao detailDao;
    @Autowired
    private ProductStockRackDao productStockRackDao;
    @Autowired
    private OrderOutputDao orderOutputDao;
    @Autowired
    private FbaOrderOutputDao fbaOrderOutputDao;
    @Autowired
    private FbaOrderOutputService fbaOrderOutputService;
    @Autowired
    private StorageDao storageDao;
    @Autowired
    private StorageService storageService;
    @Autowired
    private StorageShelfService storageShelfService;
    @Autowired
    private StoragePositionDao storagePositionDao;
    @Autowired
    private ProductInfoDao productInfoDao;
    @Autowired
    private DicBusinessItemService dicBusinessItemService;
    @Autowired
    private StockPickUpRuleDao stockPickUpRuleDao;
    @Autowired
    private StockPickUpRuleService stockPickUpRuleService;
    @Autowired
    private JpRegionService jpRegionService;


    @Value("${gbc.template.filePath}")
    private String templatePath;
    @Value("${gbc.uploadPath.filePathLocal}")
    private String filePath;
    @Value("${gbc.uploadPath.fileUrl}")
    private String fileUrl;
    @Value("${gbc.uploadPath.filePathTemp}")
    private String filePathTemp;


    @Autowired
    private ProductStockFlowingService productStockFlowingService;
    @Autowired
    private StorageShelfDao storageShelfDao;
    @Autowired
    private StockPickUpDetailDao stockPickUpDetailDao;
    @Autowired
    private StoragePositionDao positionDao;
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    private UserDao userDao;
    @Autowired
    private OrderOutputProductDao orderOutputProductDao;
    @Autowired
    private ProductStockFlowingDao productStockFlowingDao;
    @Autowired
    private CompanyDao companyDao;


    @Override
    public SingleResult addInit() {
        return SingleResult.success("");
    }

    @Override
    public Object add(Object req, Long userId) {
        StockPickUpDo entityDo = new StockPickUpDo();
        BeanUtils.copyProperties(req, entityDo);
        handlerAddBefore(entityDo, userId);
        dao.insert(entityDo);
        return handlerAddAfter(entityDo);
    }

    //新增校验
    private void addCheck(Object req) {

    }

    //做新增之前要执行的业务定制处理
    private void handlerAddBefore(StockPickUpDo entityDo, Long userId) {
        entityDo.setCreateBy(userId);
        entityDo.setCreateTime(new Date());
    }

    //将新增的do转换成要返回的实体
    private Object handlerAddAfter(StockPickUpDo entityDo) {
        Object res = new Object();
        BeanUtils.copyProperties(entityDo, res);
        return res;
    }

    @Override
    public SingleResult updateInit(Long id) {
        return SingleResult.success("");
    }

    /**
     * 修改拣货单状态
     *
     * @param req
     * @param userId
     * @return
     */
    @Override
    public String update(UpdatePickUpReq req, Long userId) {
        StringBuilder msg = new StringBuilder();
        Set<String> orderNoSet = new HashSet<>();
        StockPickUpDo pickUpDo = dao.selectById(req.getId());
        if (req.getStatus() == 0) {//取消拣货
            if (pickUpDo == null) {
                throw new BizException(SysConstant.StockPickup_NotExist);
            }
            if (pickUpDo.getStatus() == 1) {
                throw new BizException(SysConstant.StockPickup_HadPicked);
            }
            Map<Long, String> orderNoMap = new HashMap<>();//记录出库单信息

            //现在待拣货就锁定了库存， 需要回滚锁定库存
            if (pickUpDo.getType().equals("output")) {
                List<OrderOutputDo> outputList = orderOutputDao.selectList(new QueryWrapper<OrderOutputDo>().eq("pick_up_id", req.getId()));
                for (OrderOutputDo et : outputList) {
                    if (!DicBusinessItemConstant.waitingPickUp.equals(et.getStatus())) {
                        throw new BizException(SysConstant.Order_Status_WaitPickup_Error, et.getOrderOutputNumber());
                    }
                    orderNoMap.put(et.getId(), et.getOrderOutputNumber() + "-" + et.getShopId() + "-" + et.getCompanyId());
                }
            } else {
                List<FbaOrderOutputDo> fbaOutputList = fbaOrderOutputDao.selectList(new QueryWrapper<FbaOrderOutputDo>().eq("pick_up_id", req.getId()));
                for (FbaOrderOutputDo et : fbaOutputList) {
                    orderNoMap.put(et.getId(), et.getFbaOrderOutputNumber() + "-" + et.getShopId() + "-" + et.getCompanyId());
                }
            }

            List<StockPickUpDetailDo> pickUpDetailDoList = stockPickUpDetailDao.selectList(new LambdaQueryWrapper<StockPickUpDetailDo>().eq(StockPickUpDetailDo::getPickUpId, req.getId()));
            for (StockPickUpDetailDo pickUpDetailDo : pickUpDetailDoList) {
                int goodQuantity = pickUpDetailDo.getNumber();
                //解决 两个出库单 同时锁定一个库存id时，后者多的一个出库单先发货，将锁定库存发完，导致锁定库存不够
                List<ProductStockRackDo> stockRackDoList;
                synchronized (this) {
                    ProductStockRackDo stockRackDo = productStockRackDao.getOne(pickUpDetailDo.getStockRackId());
                    stockRackDoList = productStockRackDao.getLockingStockList(pickUpDetailDo.getProductId(), pickUpDo.getStorageId(), stockRackDo.getRackId());
                }
                if (stockRackDoList.stream().mapToInt(ProductStockRackDo::getGoodLockQuantity).sum() < goodQuantity) {
                    throw new BizException(SysConstant.Order_LockCount_NotEnough);
                }
                for (ProductStockRackDo rackDo : stockRackDoList) {
                    int onceCount = 0;
                    if (rackDo.getGoodLockQuantity() >= goodQuantity) {
                        onceCount = goodQuantity;
                        rackDo.setGoodLockQuantity(rackDo.getGoodLockQuantity() - goodQuantity);
                        rackDo.setGoodQuantity(rackDo.getGoodQuantity() + goodQuantity);
                        goodQuantity = 0;
                    } else {
                        onceCount = rackDo.getGoodLockQuantity();
                        goodQuantity -= rackDo.getGoodLockQuantity();
                        rackDo.setGoodLockQuantity(0);
                        rackDo.setGoodQuantity(rackDo.getGoodQuantity() + onceCount);
                    }
                    productStockRackDao.updateById(rackDo);
                    //库存流水新
                    productStockFlowingService.insertFlowing(pickUpDo.getType(), orderNoMap.get(pickUpDetailDo.getOrderOutputId()).split("-")[0], Long.parseLong(orderNoMap.get(pickUpDetailDo.getOrderOutputId()).split("-")[1]), pickUpDetailDo.getProductId(), pickUpDo.getStorageId(),
                            onceCount, 0, -onceCount, rackDo.getRackId(), Long.parseLong(orderNoMap.get(pickUpDetailDo.getOrderOutputId()).split("-")[2]), userId,
                            StaticDict.Product_Flowing_Type.Output.getValue().equals(pickUpDo.getType()) ? "出库单:" + orderNoMap.get(pickUpDetailDo.getOrderOutputId()).split("-")[0] + "取消拣货,锁定库存回滚" : "fba出库单:" + orderNoMap.get(pickUpDetailDo.getOrderOutputId()).split("-")[0] + "取消拣货,锁定库存回滚");

                    if (goodQuantity <= 0) {
                        break;
                    }
                }
                if (goodQuantity > 0) {
//                throw new BizException("锁定库存不够");
                    throw new BizException(SysConstant.Order_LockCount_NotEnough);
                }
            }
            detailDao.delete(new QueryWrapper<StockPickUpDetailDo>().eq("pick_up_id", req.getId()));
            dao.deleteById(req.getId());
            if (pickUpDo.getType().equals("output")) {
                //修改出库单状态
                orderOutputDao.updatePickUpIdNull(req.getId(), userId);
            } else {
                //修改fba出库单状态
                fbaOrderOutputDao.updatePickUpIdNull(req.getId(), userId);
            }
        } else {
            //修改拣货状态 完成拣货
            pickUpDo.setStatus(1);
            if (pickUpDo.getClaimBy() != null) {
                pickUpDo.setPickUpBy(pickUpDo.getClaimBy());
            } else {
                pickUpDo.setPickUpBy(userId);
            }
            pickUpDo.setPickUpTime(new Date());
            dao.updateById(pickUpDo);

            if ("output".equals(pickUpDo.getType())) {
                //修改出库表中的出库单的状态
                List<OrderOutputDo> outputDoList = orderOutputDao.selectList(new QueryWrapper<OrderOutputDo>().eq("pick_up_id", req.getId()));
                for (OrderOutputDo outputDo : outputDoList) {
                    if (outputDo.getStatus().equals(DicBusinessItemConstant.orderCutOff)) {
                        orderNoSet.add(outputDo.getOrderOutputNumber());
                        continue;
                    }
                    if (!outputDo.getStatus().equals(DicBusinessItemConstant.waitingPickUp)) {
                        continue;
                    }
                    outputDo.setStatus(DicBusinessItemConstant.alreadyPickUp);
                    outputDo.setUpdateBy(userId);
                    outputDo.setUpdateTime(new Date());
                    orderOutputDao.updateById(outputDo);
                }
            } else if ("fbaOutput".equals(pickUpDo.getType())) {
                List<FbaOrderOutputDo> fbaList = fbaOrderOutputDao.selectList(new LambdaQueryWrapper<FbaOrderOutputDo>()
                        .eq(FbaOrderOutputDo::getPickUpId, req.getId()));
                for (FbaOrderOutputDo et : fbaList) {
                    if (et.getPickStatus().equals(StaticDict.Pick_Up_Status.Picked.getValue())) {
                        //已拣货
                        continue;
                    }
                    et.setPickStatus(StaticDict.Pick_Up_Status.Picked.getValue());
                    et.setUpdateBy(userId);
                    et.setUpdateTime(new Date());
                    fbaOrderOutputDao.updateById(et);
                }
            }
        }
        if (orderNoSet.size() > 0) {
            msg.append(StringsUtil.createI18Message(SysConstant.StockPickup_Update_Success, StringUtils.join(orderNoSet, ",")));
//            msg.append("出库单：").append(StringUtils.join(orderNoSet, ",")).append(" 已截单, 请注意回退已截单库存");
        } else {
            msg.append("拣货成功");
        }
        return msg.toString();
    }

    @Override
    public void finishPickUp(StockPickUpDo pickUpDo, Set<String> orderNoSet, Long userId, Long orderOutputId) {
        OrderOutputDo outputDo = null;
        FbaOrderOutputDo fbaOutput = null;
        if ("output".equals(pickUpDo.getType())) {
            outputDo = orderOutputDao.selectById(orderOutputId);
            if (outputDo == null || !outputDo.getStatus().equals(DicBusinessItemConstant.waitingPickUp)) {
                return;
            }
        } else if ("fbaOutput".equals(pickUpDo.getType())) {
            fbaOutput = fbaOrderOutputDao.selectById(orderOutputId);
            if (fbaOutput == null || !fbaOutput.getPickStatus().equals(StaticDict.Pick_Up_Status.UnPick.getValue())) {
                return;
            }
        } else {
            return;
        }
        if (outputDo != null) {
            outputDo.setStatus(DicBusinessItemConstant.alreadyPickUp);
            outputDo.setUpdateBy(userId);
            outputDo.setUpdateTime(new Date());
            orderOutputDao.updateById(outputDo);
        } else {
            fbaOutput.setPickStatus(StaticDict.Pick_Up_Status.Picked.getValue());
            fbaOutput.setUpdateBy(userId);
            fbaOutput.setUpdateTime(new Date());
            fbaOrderOutputDao.updateById(fbaOutput);
        }

        //判断拣货单下 所有出库单，是否都已经拣货
        this.finishPickUpAfter(pickUpDo, userId);
    }


    @Override
    public void finishPickUpAfter(Long pickupId, Long userId) {
        StockPickUpDo pickUpDo = dao.selectById(pickupId);
        if (pickUpDo == null) {
            return;
        }
        this.finishPickUpAfter(pickUpDo, userId);
    }

    @Override
    public void finishPickUpAfter(StockPickUpDo pickUpDo, Long userId) {
        if (pickUpDo.getStatus() == 1) {
            //已拣货直接返回
            return;
        }
        //判断拣货单下 所有出库单，是否都已经拣货
        int count = 0;
        if ("output".equals(pickUpDo.getType())) {
            count = orderOutputDao.selectCount(new LambdaQueryWrapper<OrderOutputDo>().eq(OrderOutputDo::getPickUpId, pickUpDo.getId()).eq(OrderOutputDo::getStatus, DicBusinessItemConstant.waitingPickUp));
        } else if ("fbaOutput".equals(pickUpDo.getType())) {
            count = fbaOrderOutputDao.selectCount(new LambdaQueryWrapper<FbaOrderOutputDo>().eq(FbaOrderOutputDo::getPickUpId, pickUpDo.getId()).eq(FbaOrderOutputDo::getPickStatus, StaticDict.Pick_Up_Status.UnPick.getValue()));
        }
        if (count == 0) {
            pickUpDo.setStatus(1);
            pickUpDo.setPickUpBy(userId);
            pickUpDo.setPickUpTime(new Date());
            dao.updateById(pickUpDo);
        }
    }

    //出库单未拣货，获取推荐库位
    @Override
    public List<PositionAndNumberDTO> getPosList(StockPickUpDo pickUpDo, Set<String> orderNoSet, Long orderOutputId, boolean view) {
        //按照 prodcutId 出库单id 库位id 仓库id 汇总
        List<StockPickUpDetailDto> detailList = detailDao.getPickDetail(pickUpDo.getId(), orderOutputId);

        for (StockPickUpDetailDto et : detailList) {
            if ("output".equals(pickUpDo.getType())) {
                OrderOutputDo orderOutputDo = orderOutputDao.selectById(et.getOrderOutputId());
                if (orderOutputDo != null) {
                    if (orderOutputDo.getStatus().equals(DicBusinessItemConstant.orderCutOff)) {
                        orderNoSet.add(orderOutputDo.getOrderOutputNumber());
                        et.setStatus("cutOff");
                    } else if (!orderOutputDo.getStatus().equals(DicBusinessItemConstant.waitingPickUp) && !view) {
                        //view true 表示 预览
                        //非待拣货得出库单跳过
                        et.setStatus("finish");
                    }
                    et.setShopId(orderOutputDo.getShopId());
                    et.setCompanyId(orderOutputDo.getCompanyId());
                    et.setOrderNo(orderOutputDo.getOrderNo());
                } else {
                    throw new BizException(SysConstant.OrderOutput_NotMatch);
                }
            } else if ("fbaOutput".equals(pickUpDo.getType())) {
                FbaOrderOutputDo orderOutputDo = fbaOrderOutputDao.selectById(et.getOrderOutputId());
                if (orderOutputDo != null) {
                    et.setOrderNo(orderOutputDo.getFbaOrderOutputNumber());
                    et.setShopId(orderOutputDo.getShopId());
                    et.setCompanyId(orderOutputDo.getCompanyId());
                } else {
                    throw new BizException(SysConstant.OrderOutput_NotMatch_Fba);
                }
            } else {
                throw new BizException(SysConstant.StockPickup_Type_NotMatch);
            }
        }


        List<PositionAndNumberDTO> positionAndNumberList = new ArrayList<>();
        for (StockPickUpDetailDto et : detailList) {
            if ("cutOff".equals(et.getStatus()) || "finish".equals(et.getStatus())) {
                //已截单得，直接跳过
                continue;
            }
            StorageDo storageDo = storageDao.selectById(et.getStorageId());
            if (storageDo == null) {
                throw new BizException(SysConstant.Storage_NotExist);
            }
            Map<String, String> map = new HashMap<>();

            ProductInfoDo productInfoDo = productInfoDao.selectById(et.getProductId());
            if (productInfoDo == null) {
                throw new BizException(SysConstant.Product_NotExist);
            }
//            map.put("shopId", et.getShopId()+"");
            map.put("companyId", et.getCompanyId() + "");
            map.put("productId", et.getProductId() + "");
            map.put("storageId", et.getStorageId() + "");
            if (et.getRackId() == null) {
                //默认库位
                map.put("default", "default");
            } else {
                map.put("rackId", et.getRackId() + "");
            }
            if (productInfoDo.getOutType() == 1) {
                map.put("outType", productInfoDo.getOutType() + "");
            }


            //倒序获取库位货存 可做到先进先出
            List<PickupStockRackDto> stockRackList = productStockRackDao.getStockRackBySort(map);

            if (stockRackList.size() <= 0) {
                throw new BizException(SysConstant.Order_Pickup_Error_Stock, et.getOrderNo(), storageDo.getStorageName(), productInfoDo.getCommoditySku());
//                throw new BizException("入库单:" + et.getOrderNo() + ",仓库：" + storageDo.getStorageName() + ", sku:" + productInfoDo.getCommoditySku() + " 库位无库存，请核实");
            }
            int goodQuantity = et.getNumber();
            for (PickupStockRackDto st : stockRackList) {
                PositionAndNumberDTO positionAndNumberDTO = new PositionAndNumberDTO();
                //如果从库位中取库存取不够的话就继续从下一个库位中取
                positionAndNumberDTO.setProductId(et.getProductId());
                positionAndNumberDTO.setProductSku(productInfoDo.getCommoditySku());
                positionAndNumberDTO.setStorageId(et.getStorageId());
                positionAndNumberDTO.setStockRackId(st.getId());
                positionAndNumberDTO.setRackId(st.getRackId());
                positionAndNumberDTO.setStorageName(storageDo.getStorageName());
                positionAndNumberDTO.setOrderOutputId(et.getOrderOutputId());
                if (st.getGoodQuantity() > goodQuantity) {
                    positionAndNumberDTO.setNumber(goodQuantity);
                    goodQuantity = 0;
                } else {
                    positionAndNumberDTO.setNumber(st.getGoodQuantity());
                    goodQuantity -= st.getGoodQuantity();
                }
                StoragePositionDo positionDo = storagePositionDao.selectById(st.getRackId());
                //保存货架区域名称和对应的库位名称
                if (null != positionDo) {
                    positionAndNumberDTO.setPositionName(positionDo.getPositionName());

                    StorageShelfDo shelfDo = storageShelfDao.selectById(positionDo.getShelfId());
                    if (null != shelfDo) {
                        positionAndNumberDTO.setAreaName(shelfDo.getAreaName());
                    }
                } else {
                    positionAndNumberDTO.setPositionName("默认库位");
                }
                positionAndNumberList.add(positionAndNumberDTO);
                if (goodQuantity <= 0) {
                    break;
                }
            }

            if (goodQuantity > 0) {
                if (et.getRackId() == null) {
                    throw new BizException(SysConstant.StockPickup_Error_Default, storageDo.getStorageName(), productInfoDo.getCommoditySku());
//                    throw new BizException("仓库：" + storageDo.getStorageName() + ",默认库位 " + "sku:" + productInfoDo.getCommoditySku() + "库存不足");
                } else {
                    StoragePositionDo positionDo = storagePositionDao.selectById(et.getRackId());
                    if (positionDo == null) {
                        throw new BizException(SysConstant.StockPickup_Rack_NotMatch);
                    } else {
                        throw new BizException(SysConstant.StockPickup_Error_Rack);
//                        throw new BizException("仓库：" + storageDo.getStorageName() + ",库位:" + positionDo.getPositionName() + ",sku:" + productInfoDo.getCommoditySku() + "库存不足");
                    }
                }
            }
        }
        return positionAndNumberList;
    }


    //已关联拣货单 锁定了库存，获取锁定库存信息
    @Override
    public List<PositionAndNumberDTO> getPostListByOrderId(StockPickUpDo pickUpDo, Long orderId, String storageName) {
        List<PositionAndNumberDTO> positionAndNumberList = new ArrayList<>();
        List<StockPickUpDetailDo> pickUpDetailDoList = stockPickUpDetailDao.selectList(new LambdaQueryWrapper<StockPickUpDetailDo>()
                .eq(StockPickUpDetailDo::getPickUpId, pickUpDo.getId()).eq(StockPickUpDetailDo::getOrderOutputId, orderId));
        for (StockPickUpDetailDo et : pickUpDetailDoList) {
            PositionAndNumberDTO dto = new PositionAndNumberDTO();

            ProductInfoDo productInfoDo = productInfoDao.selectById(et.getProductId());
            if (productInfoDo == null) {
                throw new BizException(SysConstant.Product_NotExist);
            }
            ProductStockRackDo rackDo = productStockRackDao.getOne(et.getStockRackId());
            if (rackDo == null) {
                throw new BizException(SysConstant.StockPickup_LockStock_NotMatch_Sku, productInfoDo.getCommoditySku());
//                throw new BizException("sku:" + productInfoDo.getCommoditySku() + "未匹配锁定库存");
            }

            dto.setProductId(et.getProductId());
            dto.setProductSku(productInfoDo.getCommoditySku());
            dto.setStorageId(pickUpDo.getStorageId());
            dto.setStockRackId(rackDo.getId());
            dto.setRackId(rackDo.getRackId());
            dto.setStorageName(storageName);
            dto.setOrderOutputId(et.getOrderOutputId());
            dto.setNumber(et.getNumber());
            StoragePositionDo positionDo = storagePositionDao.selectById(rackDo.getRackId());
            //保存货架区域名称和对应的库位名称
            if (null != positionDo) {
                dto.setPositionName(positionDo.getPositionName());

                StorageShelfDo shelfDo = storageShelfDao.selectById(positionDo.getShelfId());
                if (null != shelfDo) {
                    dto.setAreaName(shelfDo.getAreaName());
                }
            } else {
                dto.setPositionName("默认库位");
            }
            positionAndNumberList.add(dto);
        }
        return positionAndNumberList;
    }

    //编辑校验
    private void updateCheck(Object req) {

    }

    //做修改之前要执行的业务定制处理
    private void handlerUpdateBefore(StockPickUpDo entityDo, Long userId) {
        entityDo.setUpdateBy(userId);
        entityDo.setUpdateTime(new Date());
    }

    //做修改之后要执行的业务定制处理
    private Object handlerUpdateAfter(StockPickUpDo entityDo) {
        Object res = new Object();
        BeanUtils.copyProperties(entityDo, res);
        return res;
    }

    @Override
    public int delete(Long id, Long userId) {
        StockPickUpDo entityDo = dao.selectById(id);
        handlerDeleteBefore(entityDo, userId);
        return dao.deleteById(id);
    }

    //做删除之前要执行的业务定制处理
    private void handlerDeleteBefore(StockPickUpDo entityDo, Long userId) {
    }

    @Override
    public Object detail(Long id) {
        StockPickUpDo entityDo = dao.selectById(id);
        Object res = new Object();
        BeanUtils.copyProperties(entityDo, res);
        return handlerDetailAfter(res);
    }

    //查询明细之后要执行的业务定制处理
    private Object handlerDetailAfter(Object res) {
        return res;
    }

    @Override
    public SingleResult pageInit() {
        Map<String, Object> result = new HashMap<>();
        result.put("storageList", storageService.getStorageList());
        result.put("trackList", dicBusinessItemService.getDicItemList(DicBusinessConstant.trackCompany));
        return SingleResult.success(result);
    }

    @Override
    public List<Object> getList(Map<String, String> map) {
        QueryWrapper<StockPickUpDo> wrapper = queryBuild(map);
        List<StockPickUpDo> list = this.list(wrapper);
        List<Object> result = handlerListAfter(list);
        return result;
    }

    @Override
    public PageResult getListPage(Map<String, String> map) {
        IPage<StockPickUpDto> page = pageInit(map);
        List<StockPickUpDto> resList = dao.getPickUpList(page, map);
        //子级分组合并 按库位和sku
        this.handlderListAfter(resList, map.get("sortType"));
        PageResult result = new PageResult(resList, (int) page.getCurrent(), (int) page.getSize(), (int) page.getTotal(), (int) page.getPages());
        return result;
    }

    public void handlderListAfter(List<StockPickUpDto> resList) {
        this.handlderListAfter(resList, "rack");
    }

    public void handlderListAfter(List<StockPickUpDto> resList, String sortType) {
        for (StockPickUpDto et : resList) {
            List<StockPickUpItem> list = this.getShowList(et);
            List<StockPickUpItem> pickupItemResList = new ArrayList<>();
            if ("rack".equals(sortType)) {
                Map<Integer, List<StockPickUpItem>> sortMapList = list.stream().filter(i -> i.getSort() != null).collect(Collectors.groupingBy(StockPickUpItem::getSort));
                for (Integer shelf : sortMapList.keySet()) {
                    List<StockPickUpItem> shelfList = sortMapList.get(shelf);

                    Collections.sort(shelfList, new Comparator<StockPickUpItem>() {
                        @Override
                        public int compare(StockPickUpItem o1, StockPickUpItem o2) {
                            return stockPickUpSort(o1, o2);
                        }
                    });
                    pickupItemResList.addAll(shelfList);
                }
                list.stream().filter(i -> i.getSort() == null).forEach(pickupItemResList::add);

            } else {
                pickupItemResList.addAll(list);
            }
            et.setShowList(pickupItemResList);
            et.setNumberAll(list.stream().mapToInt(StockPickUpItem::getNumber).sum());
            et.setAlreadyPickUpNumberAll(list.stream().mapToInt(StockPickUpItem::getAlreadyPickUpNumber).sum());
            if (et.getType().equals("output")) {
                et.setOrderTypeCN(StringsUtil.createI18Message(et.getOrderTypeCN()));
            }
            et.setStatusCN(StringsUtil.createI18Message(et.getStatusCN()));
        }
    }


    @Override
    public void exportExcel(Long id, String sortType, HttpServletResponse response) throws IOException {
        Map<String, String> map = new HashMap<>();
        map.put("id", id + "");
        List<StockPickUpDto> list = dao.getPickUpList(map);
        if (list.size() < 1) {
            throw new BizException(SysConstant.Pls_Choose_Data);
        }
        StockPickUpDto et = list.get(0);    //精确查找 只能有一条 共用dao层方法
        if ("output".equals(et.getType())) {
            //存放拣货单主表信息
            StockPickUpExportVo exportVo = new StockPickUpExportVo();

            BeanUtils.copyProperties(et, exportVo);
            //处理拣货单条形码
            ImageEntity imageEntity = new ImageEntity();
            imageEntity.setUrl(BarCodeUtils.createCodeImage(et.getPickUpNum(), filePathTemp, et.getPickUpNum() + ".png"));
            imageEntity.setWidth(10);
            imageEntity.setHeight(7);
            imageEntity.setColspan(3);
            imageEntity.setRowspan(2);
            exportVo.setImageEntity(imageEntity);
            //存放拣货单详情表信息
            List<StockPickUpExportVo> resList = new ArrayList<>();
            Map<String, List<StockPickUpItem>> collect = et.getItemList().stream()
                    .collect(Collectors.groupingBy(StockPickUpItem::getSkuSort));
            Set<String> sortSet = new TreeSet<String>(new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                    return o1.compareTo(o2);
                }
            });
            sortSet.addAll(collect.keySet());
            for (String key : sortSet) {
                StockPickUpExportVo exportVo2 = new StockPickUpExportVo();
                List<StockPickUpItem> keyList = collect.get(key);
                exportVo2.setStorageName(keyList.get(0).getStorageName());
                exportVo2.setName(keyList.get(0).getName());
                exportVo2.setPositionName(keyList.get(0).getPositionName());
                exportVo2.setSku(keyList.get(0).getSku());
                exportVo2.setStorageSku(keyList.get(0).getStorageSku());
                exportVo2.setRackSort(keyList.get(0).getRackSort());
                exportVo2.setSort(keyList.get(0).getSort());
                exportVo2.setNumber(keyList.stream().mapToInt(StockPickUpItem::getWaitingPickUpNumber).sum());
//                exportVo2.setCutOffNumber(keyList.stream().mapToInt(StockPickUpItem::getCutOffNumber).sum());
//                exportVo2.setAlreadyPickUpNumber(keyList.stream().mapToInt(StockPickUpItem::getAlreadyPickUpNumber).sum());
                resList.add(exportVo2);
            }

            List<StockPickUpExportVo> pickupItemResList = new ArrayList<>();
            if ("sku".equals(sortType)) {
                pickupItemResList.addAll(resList);
            } else {
                Map<Integer, List<StockPickUpExportVo>> sortMapList = resList.stream().filter(i -> i.getSort() != null).collect(Collectors.groupingBy(StockPickUpExportVo::getSort));
                for (Integer shelf : sortMapList.keySet()) {
                    List<StockPickUpExportVo> shelfList = sortMapList.get(shelf);

                    Collections.sort(shelfList, new Comparator<StockPickUpExportVo>() {
                        @Override
                        public int compare(StockPickUpExportVo o1, StockPickUpExportVo o2) {
                            return stockPickUpSort(o1, o2);
                        }
                    });
                    pickupItemResList.addAll(shelfList);
                }
                resList.stream().filter(i -> i.getSort() == null).forEach(pickupItemResList::add);
            }
            //合计数量
            exportVo.setNumberAll(resList.stream().mapToInt(StockPickUpExportVo::getNumber).sum());

            // 获取模板文件路径
            TemplateExportParams params = new TemplateExportParams(templatePath + "stock_pick_up.xls");
            //设置sheetName，若不设置该参数，则使用得原本得sheet名称
            Map<String, Object> data = new HashMap<String, Object>();
            data.put("title", et.getStorageName() + "(" + et.getOrderTypeCN() + ")"
                    + TimeUtils.formatDate(et.getCreateTime(), "MM/dd")
                    + et.getTrackName() + "拣货单");   //首行标题
            data.put("exportVo", exportVo);
            data.put("list", pickupItemResList);
            // 获取workbook
            Workbook workbook = ExcelExportUtil.exportExcel(params, data);
            try {
                ExcelUtils.downLoadExcel("拣货单" + exportVo.getPickUpNum(), response, workbook);
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            fbaOrderOutputService.exportPickUp(Arrays.asList(id), response);
        }
    }

    public int stockPickUpSort(StockPickUpSort o1, StockPickUpSort o2) {
        if (o1.getSort() == null && o2.getSort() != null) {
            return 1;
        } else if (o2.getSort() == null && o1.getSort() != null) {
            return -1;
        } else if (o1.getSort() != null && o2.getSort() != null && !o1.getSort().equals(o2.getSort())) {
            return o1.getSort() - o2.getSort();
        } else {
            if (o1.getRackSort() == null) {
                return 1;
            } else if (o2.getRackSort() == null) {
                return -1;
            } else if (o1.getRackSort().equals(o2.getRackSort())) {
                return o1.getSku().compareTo(o2.getSku());
            } else {
                return o1.getRackSort().compareTo(o2.getRackSort());
            }
        }
    }

    //查询分页列表之后对列表数据的处理
    private List<Object> handlerListAfter(List<StockPickUpDo> list) {
        List<Object> result = new ArrayList<>();
        return result;
    }

    private IPage<StockPickUpDto> pageInit(Map<String, String> map) {
        IPage<StockPickUpDto> page = new Page();
        page.setSize(StringUtils.isNotBlank(map.get("pageSize")) ? Long.parseLong(map.get("pageSize")) : 10);
        page.setCurrent(StringUtils.isNotBlank(map.get("current")) ? Long.parseLong(map.get("current")) : 1);
        return page;
    }

    private QueryWrapper<StockPickUpDo> queryBuild(Map<String, String> map) {
        QueryWrapper<StockPickUpDo> wrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(map.get("keyword"))) {
            wrapper.like("keyword", map.get("keyword"));
        }
        return wrapper;
    }


    @Override
    public int getPositionAndNumberDTO(List<PositionAndNumberDTO> positionAndNumberList, PickupStockRackDto st, ProductInfoDo productInfoDo, StorageDo storageDo, int goodQuantity, Long orderId) {
        PositionAndNumberDTO positionAndNumberDTO = new PositionAndNumberDTO();
        //如果从库位中取库存取不够的话就继续从下一个库位中取
        positionAndNumberDTO.setProductId(productInfoDo.getId());
        positionAndNumberDTO.setProductSku(productInfoDo.getCommoditySku());
        positionAndNumberDTO.setStorageId(storageDo.getId());
        positionAndNumberDTO.setStockRackId(st.getId());
        positionAndNumberDTO.setRackId(st.getRackId());
        positionAndNumberDTO.setStorageName(storageDo.getStorageName());
        positionAndNumberDTO.setOrderOutputId(orderId);
        positionAndNumberDTO.setSort(st.getSort());
        positionAndNumberDTO.setRackSort(st.getRackSort());
        if (st.getGoodQuantity() > goodQuantity) {
            positionAndNumberDTO.setNumber(goodQuantity);
            st.setGoodQuantity(st.getGoodQuantity() - goodQuantity);
            goodQuantity = 0;
        } else {
            positionAndNumberDTO.setNumber(st.getGoodQuantity());
            goodQuantity -= st.getGoodQuantity();
            st.setGoodQuantity(0);
        }
        StoragePositionDo positionDo = storagePositionDao.selectById(st.getRackId());
        //保存货架区域名称和对应的库位名称
        if (null != positionDo) {
            positionAndNumberDTO.setPositionName(positionDo.getPositionName());

            StorageShelfDo shelfDo = storageShelfDao.selectById(positionDo.getShelfId());
            if (null != shelfDo) {
                positionAndNumberDTO.setAreaName(shelfDo.getAreaName());
            }
        } else {
            positionAndNumberDTO.setPositionName("默认库位");
        }
        positionAndNumberList.add(positionAndNumberDTO);
        return goodQuantity;
    }

    @Override
    public List<PositionAndNumberDTO> getShowList(List<PositionAndNumberDTO> positionAndNumberList) {
        List<PositionAndNumberDTO> list = new ArrayList<>();
        Map<String, List<PositionAndNumberDTO>> collect = positionAndNumberList.stream().collect(Collectors.groupingBy(t -> t.getProductId() + "-" + t.getStorageId() + "-" + t.getRackId()));
        for (String key : collect.keySet()) {
            PositionAndNumberDTO res = new PositionAndNumberDTO();
            List<PositionAndNumberDTO> keyList = collect.get(key);

            res.setStorageName(keyList.get(0).getStorageName());
            res.setAreaName(keyList.get(0).getAreaName());
            res.setRackId(keyList.get(0).getRackId());
            res.setStorageId(keyList.get(0).getStorageId());
            res.setPositionName(keyList.get(0).getPositionName());
            res.setNumber(keyList.stream().mapToInt(PositionAndNumberDTO::getNumber).sum());
            res.setProductId(keyList.get(0).getProductId());
            res.setProductSku(keyList.get(0).getProductSku());
            res.setStockRackId(keyList.get(0).getStockRackId());
            res.setOrderOutputId(keyList.get(0).getOrderOutputId());
            res.setSort(keyList.get(0).getSort());
            res.setRackSort(keyList.get(0).getRackSort());
            list.add(res);
        }
        List<PositionAndNumberDTO> resList = new ArrayList<>();
        Map<Integer, List<PositionAndNumberDTO>> sortMapList = list.stream().filter(i -> i.getSort() != null).collect(Collectors.groupingBy(PositionAndNumberDTO::getSort));
        for (Integer shelf : sortMapList.keySet()) {
            List<PositionAndNumberDTO> shelfList = sortMapList.get(shelf);

            Collections.sort(shelfList, new Comparator<PositionAndNumberDTO>() {
                @Override
                public int compare(PositionAndNumberDTO o1, PositionAndNumberDTO o2) {
                    if (o1.getSort() == null && o2.getSort() != null) {
                        return 1;
                    } else if (o2.getSort() == null && o1.getSort() != null) {
                        return -1;
                    } else if (o1.getSort() != null && o2.getSort() != null && !o1.getSort().equals(o2.getSort())) {
                        return o1.getSort() - o2.getSort();
                    } else {
                        if (o1.getRackSort() == null) {
                            return 1;
                        } else if (o2.getRackSort() == null) {
                            return -1;
                        } else {
                            return o1.getRackSort() - o2.getRackSort();
                        }
                    }

                    //此方法按照库位在最后一个数字排序的
//                String[] o1Name = o1.getPositionName().split("-");
//                String[] o2Name = o2.getPositionName().split("-");
//                if (o1Name.length == 1 && o2Name.length != 1) {
//                    return 1;
//                } else if (o1Name.length != 1 && o2Name.length == 1) {
//                    return -1;
//                } else if (o1Name.length == 1) {
//                    if (o1.getStockRackId() >= o2.getStockRackId()) {
//                        return 1;
//                    } else {
//                        return -1;
//                    }
//                } else {
//                    if (o1Name.length < 3) {
//                        return 1;
//                    }
//                    if (o2Name.length < 3) {
//                        return -1;
//                    }
//                    if (Integer.parseInt(o1Name[2]) > Integer.parseInt(o2Name[2])) {
//                        return 1;
//                    } else if (Integer.parseInt(o1Name[2]) < Integer.parseInt(o2Name[2])) {
//                        return -1;
//                    } else {
//                        if (Integer.parseInt(o1Name[1]) >= Integer.parseInt(o2Name[1])) {
//                            return 1;
//                        } else if (Integer.parseInt(o1Name[1]) < Integer.parseInt(o2Name[1])) {
//                            return -1;
//                        }
//                    }
//                }
//                return 0;
                }
            });
            resList.addAll(shelfList);
        }

        list.stream().filter(i -> i.getSort() == null).forEach(resList::add);
        return resList;
    }


    @Override
    public void deletePickUp(Long pickUpId, Long orderId) {
        //未拣货 删掉关联
        LambdaQueryWrapper<StockPickUpDetailDo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(StockPickUpDetailDo::getPickUpId, pickUpId);
        queryWrapper.eq(StockPickUpDetailDo::getOrderOutputId, orderId);
        stockPickUpDetailDao.delete(queryWrapper);
        int count = stockPickUpDetailDao.selectCount(new LambdaQueryWrapper<StockPickUpDetailDo>().eq(StockPickUpDetailDo::getPickUpId, pickUpId));
        if (count == 0) {
            //拣货单没有子集，删除自身
            dao.deleteById(pickUpId);
        }


    }

    /**
     * 拣货单修改 获取库位 下拉框,根据 商品 、仓库、公司
     */
    @Override
    public List<RackStockRes> getRackStock(Long id, Long productId, Long storageId) {
        Map<String, String> param = new HashMap<>();
        param.put("id", id + "");
        List<StockPickUpDto> list = dao.getPickUpList(param);
        this.handlderListAfter(list);

        ProductInfoDo productInfoDo = productInfoDao.selectById(productId);
        if (productInfoDo == null) {
            throw new BizException(SysConstant.Product_NotExist);
        }
        Map<String, String> map = new HashMap<>();
        map.put("productId", productId + "");
        map.put("storageId", storageId + "");
        map.put("companyId", productInfoDo.getCompanyId() + "");
        if (productInfoDo.getOutType() == 1) {
            map.put("outType", productInfoDo.getOutType() + "");
        }

        List<PickupStockRackDto> stockRackList;
        //倒序获取库位货存 可做到先进先出
        synchronized (this) {
            stockRackList = productStockRackDao.getStockRackBySort(map);
        }

        Map<Long, Integer> stockMap = new HashMap<>();
        for (PickupStockRackDto stockRackDo : stockRackList) {
            stockMap.merge(stockRackDo.getRackId(), stockRackDo.getGoodQuantity(), Integer::sum);
        }
        List<RackStockRes> resList = new ArrayList<>();
        for (Long key : stockMap.keySet()) {
            RackStockRes res = new RackStockRes();
            res.setId(key);

            if (key == null) {
                res.setPositionName("默认库位");
            } else {
                StoragePositionDo positionDo = storagePositionDao.selectById(key);
                if (positionDo == null) {
                    throw new BizException(SysConstant.Rack_NotExist);
                }
                res.setPositionName(positionDo.getPositionName());
            }
            res.setGoodQuantity(stockMap.get(key));
            if (list.size() > 0) {
                for (StockPickUpItem stockPickUpItem : list.get(0).getShowList()) {
                    if (stockPickUpItem.getProductId().equals(productId) &&
                            ((stockPickUpItem.getRackId() == null && key == null) || (stockPickUpItem.getRackId() != null && stockPickUpItem.getRackId().equals(key)) || (key != null && key.equals(stockPickUpItem.getRackId()))) &&
                            list.get(0).getStorageId().equals(storageId)) {
                        res.setGoodQuantity(res.getGoodQuantity() + stockPickUpItem.getNumber());
                    }
                }
            }
            resList.add(res);
        }
        return resList;
    }


    @Override
    public StockPickUpDto updatePickUpInit(Long id, String sortType) {
        Map<String, String> map = new HashMap<>();
        map.put("id", id + "");
        List<StockPickUpDto> list = dao.getPickUpList(map);
        if (list.size() < 1) {
            throw new BizException(SysConstant.StockPickup_NotExist);
        }
        if (list.get(0).getStatus() == 1) {
            throw new BizException(SysConstant.StockPickup_Update_HadPicked);
        }
        this.handlderListAfter(list, sortType);
        for (StockPickUpItem stockPickUpItem : list.get(0).getShowList()) {
            Map<String, String> param = new HashMap<>();
            if (stockPickUpItem.getRackId() != null) {
                param.put("rackId", stockPickUpItem.getRackId() + "");
            }
            param.put("productId", stockPickUpItem.getProductId() + "");
            param.put("storageId", list.get(0).getStorageId() + "");
            param.put("store", "0");
            ProductStockDetailDto detailDto = productStockRackDao.getStockByRackId(param);
            if (detailDto != null) {
                stockPickUpItem.setRackGoodQuantity(detailDto.getGoodQuantity() + stockPickUpItem.getNumber());
            }
        }
        return list.get(0);
    }

    @Override
    public void updatePickUp(StockPickUpdateReq req, Long userId) {
        Map<String, Integer> reqMap = new HashMap<>();
        Map<Long, Integer> checkMap = new HashMap<>();
        for (StockPickUpdateItemReq item : req.getItems()) {
            if (item.getGoodQuantity() <= 0) {
                continue;
            }
            reqMap.merge(item.getProductId() + "_" + item.getRackId(), item.getGoodQuantity(), Integer::sum);
            checkMap.merge(item.getProductId(), item.getGoodQuantity(), Integer::sum);
        }
        Map<String, String> map = new HashMap<>();
        map.put("id", req.getId() + "");
        List<StockPickUpDto> list = dao.getPickUpList(map);
        if (list.size() < 1) {
            throw new BizException(SysConstant.StockPickup_NotExist);
        }
        if (list.get(0).getStatus() == 1) {
            throw new BizException(SysConstant.StockPickup_Update_HadPicked);
        }
        StorageDo storageDo = storageDao.selectById(list.get(0).getStorageId());
        if (storageDo == null) {
            throw new BizException(SysConstant.Storage_NotExist);
        }
        //待拣货detail集合
        List<StockPickUpItem> itemList = new ArrayList<>();
        for (StockPickUpItem stockPickUpItem : list.get(0).getItemList()) {
            if ("output".equals(list.get(0).getType())) {
                OrderOutputDo et = orderOutputDao.selectById(stockPickUpItem.getOrderOutputId());
                if (et == null) {
                    throw new BizException(SysConstant.OrderOutput_NotMatch);
                }
                if (et.getStatus().equals(DicBusinessItemConstant.outCreateState)
                        || et.getStatus().equals(DicBusinessItemConstant.outCreateCheckState) || et.getStatus().equals(DicBusinessItemConstant.waitingPickUp)) {
                    itemList.add(stockPickUpItem);
                }
            } else {
                FbaOrderOutputDo et = fbaOrderOutputDao.selectById(stockPickUpItem.getOrderOutputId());
                if (et == null) {
                    throw new BizException(SysConstant.OrderOutput_NotMatch_Fba);
                }

                if (!(StaticDict.Pick_Up_Status.Picked.getValue().equals(et.getPickStatus()) && et.getPickUpId() != null)) {
                    itemList.add(stockPickUpItem);
                }
            }
        }
        if (itemList.size() == 0) {
            return;
        }

        //校验产品的拣货数量 和修改之前的总数 是否一致
        for (Long key : checkMap.keySet()) {
            int quantity = itemList.stream().filter(i -> i.getProductId().equals(key)).mapToInt(StockPickUpItem::getNumber).sum();
            if (quantity != checkMap.get(key)) {
                ProductInfoDo productInfoDo = productInfoDao.selectById(key);
                throw new BizException(SysConstant.StockPickup_Update_Count_Error_Sku, productInfoDo.getCommoditySku());
//                throw new BizException(productInfoDo.getCommoditySku() + " 待拣货数量不正确");
            }
        }

        Map<String, Integer> rollRecordMap = new HashMap<>();//流水记录用 productId_rackId_orderId
        //先将锁定库存统一返回。再去锁定库存
        for (StockPickUpItem stockPickUpItem : itemList) {
            rollRecordMap.merge(stockPickUpItem.getProductId() + "_" + stockPickUpItem.getRackId() + "_" + stockPickUpItem.getOrderOutputId(), -stockPickUpItem.getNumber(), Integer::sum);
            int lockQuantity = stockPickUpItem.getNumber();
            //锁定库存不够 用其他的库位一致的锁定库存
            List<ProductStockRackDo> stockRackDoList = productStockRackDao.getLockingStockList(stockPickUpItem.getProductId(), list.get(0).getStorageId(), stockPickUpItem.getRackId());
            for (ProductStockRackDo stockRackDo : stockRackDoList) {//锁定库存回滚
                if (stockRackDo.getGoodLockQuantity() >= lockQuantity) {
                    stockRackDo.setGoodLockQuantity(stockRackDo.getGoodLockQuantity() - lockQuantity);
                    stockRackDo.setGoodQuantity(stockRackDo.getGoodQuantity() + lockQuantity);
                    lockQuantity = 0;
                } else {
                    lockQuantity -= stockRackDo.getGoodLockQuantity();
                    stockRackDo.setGoodQuantity(stockRackDo.getGoodQuantity() + stockRackDo.getGoodLockQuantity());
                    stockRackDo.setGoodLockQuantity(0);
                }
                productStockRackDao.updateById(stockRackDo);
                if (lockQuantity <= 0) {
                    break;
                }
            }
            if (lockQuantity > 0) {
                throw new BizException(SysConstant.Order_LockCount_NotEnough);
            }
        }

        //先删除再去 插入新的
        stockPickUpDetailDao.delete(new LambdaQueryWrapper<StockPickUpDetailDo>()
                .eq(StockPickUpDetailDo::getPickUpId, req.getId())
                .in(StockPickUpDetailDo::getOrderOutputId, itemList.stream().map(StockPickUpItem::getOrderOutputId).collect(Collectors.toList())));

        Map<String, Integer> orderCountMap = new HashMap<>();
        //记录每个订单要锁定多少个库存 给 拣货单详情用
        for (StockPickUpItem stockPickUpItem : itemList) {
            orderCountMap.merge(stockPickUpItem.getProductId() + "_" + stockPickUpItem.getOrderOutputId(), stockPickUpItem.getNumber(), Integer::sum);
        }
        Map<String, List<StockPickUpItem>> itemListMap = itemList.stream().collect(Collectors.groupingBy(i -> i.getProductId() + "-" + i.getOrderOutputId()));
//        Map<String, List<StockPickUpItem>> itemListMap = itemList.stream().collect(Collectors.groupingBy(i -> i.getProductId() + ""));

        for (String key : reqMap.keySet()) {//key item.getProductId()+"_"+item.getRackId()
            ProductInfoDo productInfoDo = productInfoDao.selectById(key.split("_")[0]);
            //获取库存
            Map<String, String> param = new HashMap<>();
            param.put("productId", key.split("_")[0]);
            param.put("storageId", list.get(0).getStorageId() + "");
            param.put("companyId", productInfoDo.getCompanyId() + "");
            if ("null".equals(key.split("_")[1])) {
                //默认库位
                param.put("default", "default");
            } else {
                param.put("rackId", key.split("_")[1]);
            }
            if (productInfoDo.getOutType() == 1) {
                map.put("outType", productInfoDo.getOutType() + "");
            }

            List<PickupStockRackDto> stockRackBySort = productStockRackDao.getStockRackBySort(param);//productId rackId 下所有库存

            int goodQuantity = reqMap.get(key); //req 的数量

            for (PickupStockRackDto stockRackDo : stockRackBySort) {
                if (stockRackDo.getGoodQuantity() <= 0) {
                    continue;
                }
                int onceCount = 0;
                if (stockRackDo.getGoodQuantity() >= goodQuantity) {
                    onceCount = goodQuantity;
                    stockRackDo.setGoodQuantity(stockRackDo.getGoodQuantity() - goodQuantity);
                    goodQuantity = 0;
                } else {
                    onceCount = stockRackDo.getGoodQuantity();
                    goodQuantity -= stockRackDo.getGoodQuantity();
                    stockRackDo.setGoodQuantity(0);
                }
                if (onceCount == 0) {
                    continue;
                }
                stockRackDo.setGoodLockQuantity(stockRackDo.getGoodLockQuantity() + onceCount);
                productStockRackDao.updateById(stockRackDo);


                for (String productIdAndOrderId : orderCountMap.keySet()) {
                    if (productIdAndOrderId.split("_")[0].equals(key.split("_")[0])) {
                        orderCountMap.merge(productIdAndOrderId, -onceCount, Integer::sum);
                        if (orderCountMap.get(productIdAndOrderId) < 0) {
                            throw new BizException(SysConstant.StockPickup_Update_Count_Error_Sku, productInfoDo.getCommoditySku());
                        }

                        //添加到拣货详情表
                        StockPickUpDetailDo pickUpDetailDo = new StockPickUpDetailDo();
                        pickUpDetailDo.setPickUpId(list.get(0).getId());
                        pickUpDetailDo.setProductId(Long.parseLong(key.split("_")[0]));
                        pickUpDetailDo.setStockRackId(stockRackDo.getId());
                        pickUpDetailDo.setNumber(onceCount);
                        //订单id
                        pickUpDetailDo.setOrderOutputId(Long.parseLong(productIdAndOrderId.split("_")[1]));
                        stockPickUpDetailDao.insert(pickUpDetailDo);

                        //库存流水
                        rollRecordMap.merge(key + "_" + pickUpDetailDo.getOrderOutputId(), onceCount, Integer::sum);
                    }
                }


                if (goodQuantity <= 0) {
                    break;
                }
            }
            if (goodQuantity > 0) {
                if ("null".equals(key.split("_")[1])) {
                    //默认库位
//                        throw new BizException("sku:" + productInfoDo.getCommoditySku() + ",默认库位库存不足");
                    throw new BizException(SysConstant.StockPickup_Error_Default, storageDo.getStorageName(), productInfoDo.getCommoditySku());

                } else {
                    StoragePositionDo rackDo = storagePositionDao.selectById(key.split("_")[1]);
                    throw new BizException(SysConstant.StockPickup_Error_Rack, storageDo.getStorageName(), (rackDo != null ? rackDo.getPositionName() : ""), productInfoDo.getCommoditySku());
//                        throw new BizException("sku:" + productInfoDo.getCommoditySku() + (rackDo != null ? ","+rackDo.getPositionName() : "")+"库存不足");
                }
            }
        }

        for (String s : rollRecordMap.keySet()) { //key product_rackId_orderId
            if (rollRecordMap.get(s) == 0) {
                continue;
            }
            int quantity = rollRecordMap.get(s);
            String s1 = s.split("_")[1];
            Long flowingRackId = null;
            if (!(StringUtils.isBlank(s1) || "null".equals(s1))) {
                flowingRackId = Long.parseLong(s1);
            }
            String flowingNoteNo = "";
            Long flowingCompanyId = null;
            Long flowingShopId = null;
            if ("output".equals(list.get(0).getType())) {
                OrderOutputDo et = orderOutputDao.selectById(s.split("_")[2]);
                if (et == null) {
                    throw new BizException(SysConstant.Order_Stock_NotMatch);
                }
                flowingNoteNo = et.getOrderOutputNumber();
                flowingCompanyId = et.getCompanyId();
                flowingShopId = et.getShopId();
            } else {
                FbaOrderOutputDo et = fbaOrderOutputDao.selectById(s.split("_")[2]);
                if (et == null) {
                    throw new BizException(SysConstant.Order_Stock_NotMatch);
                }
                flowingNoteNo = et.getFbaOrderOutputNumber();
                flowingCompanyId = et.getCompanyId();
                flowingShopId = et.getShopId();
            }

            String flowingTips = null;
            if (rollRecordMap.get(s) > 0) {
                flowingTips = "拣货单:" + list.get(0).getPickUpNum() + "修改, 锁定库存";
            } else {
                flowingTips = "拣货单:" + list.get(0).getPickUpNum() + "修改, 释放锁定库存";
            }
            productStockFlowingService.insertFlowing(list.get(0).getType(), flowingNoteNo, flowingShopId, Long.parseLong(s.split("_")[0]), list.get(0).getStorageId(),
                    -quantity, 0, quantity, flowingRackId, flowingCompanyId, userId, flowingTips);
        }
    }

    public List<StockPickUpItem> getShowList(StockPickUpDto et) {
        List<StockPickUpItem> list = new ArrayList<>();
        Map<String, List<StockPickUpItem>> collect = et.getItemList().stream().collect(Collectors.groupingBy(StockPickUpItem::getSkuSort));
        Set<String> sortSet = new TreeSet<String>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });
        sortSet.addAll(collect.keySet());
        for (String key : sortSet) {
            StockPickUpItem item = new StockPickUpItem();
            List<StockPickUpItem> keyList = collect.get(key);
            item.setId(keyList.get(0).getId());
            item.setOrderOutputId(keyList.get(0).getOrderOutputId());
            item.setProductId(keyList.get(0).getProductId());
            item.setRackId(keyList.get(0).getRackId());
            item.setSku(keyList.get(0).getSku());
            item.setStorageSku(keyList.get(0).getStorageSku());
            item.setName(keyList.get(0).getName());
            item.setPositionName(keyList.get(0).getPositionName());
            item.setStorageName(keyList.get(0).getStorageName());
            item.setNumber(keyList.stream().mapToInt(StockPickUpItem::getWaitingPickUpNumber).sum());
            item.setCutOffNumber(keyList.stream().mapToInt(StockPickUpItem::getCutOffNumber).sum());
            item.setAlreadyPickUpNumber(keyList.stream().mapToInt(StockPickUpItem::getAlreadyPickUpNumber).sum());
            item.setCompanyId(keyList.get(0).getCompanyId());
            item.setRackSort(keyList.get(0).getRackSort());
            item.setShelfId(keyList.get(0).getShelfId());
            item.setSort(keyList.get(0).getSort());
            list.add(item);
        }
        return list;
    }


    /**
     * 拣货单拣货路线预览
     */
    @Override
    public StockPickupPreviewRes pickUpPreview(Long id) {
        Map<String, String> map = new HashMap<>();
        map.put("id", id + "");
        List<StockPickUpDto> resList = dao.getPickUpList(map);
        if (resList.size() == 0) {
            throw new BizException(SysConstant.Error_Data_NotExist);
        }
        for (StockPickUpDto et : resList) {
            et.setShowList(this.getShowList(et));
        }

        List<PickupPreviewRes> previewResList = new ArrayList<>();
        Map<Long, List<StockPickUpItem>> listMap = resList.get(0).getShowList().stream().filter(i -> i.getShelfId() != null).collect(Collectors.groupingBy(StockPickUpItem::getShelfId));

        //统计默认库位上的货物
        List<Item> defaultItems = new ArrayList<>();
        resList.get(0).getItemList().stream().filter(i -> i.getShelfId() == null).forEach(i -> {
            defaultItems.add(new Item(i.getSku(), i.getNumber(), "默认库位"));
        });

        for (Long shelfId : listMap.keySet()) {
            StorageShelfDo shelfDo = storageShelfDao.selectById(shelfId);
            if (shelfDo == null) {
                continue;
            }
            if (shelfDo.getGangway() == null || shelfDo.getShelfSort() == null || shelfDo.getFirstType() == null) {
                continue;
            }

            List<StockPickUpItem> shelfItemList = listMap.get(shelfId);
            Map<String, List<StockPickUpItem>> positionItemMap = shelfItemList.stream().collect(Collectors.groupingBy(StockPickUpItem::getPositionName));

            List<ShelfSortUpdateDto> list = positionDao.getSortPosList(shelfId);
            for (ShelfSortUpdateDto dto : list) {
                if (positionItemMap.get(dto.getPositionName()) != null) {
                    List<Item> items = new ArrayList<>();
                    for (StockPickUpItem stockPickUpItem : positionItemMap.get(dto.getPositionName())) {
                        items.add(new Item(stockPickUpItem.getSku(), stockPickUpItem.getNumber(), stockPickUpItem.getPositionName()));
                    }
                    dto.setItems(items.stream().collect(Collectors.groupingBy(Item::getPositionName)));
                }
            }

            if (shelfDo.getConfig() == 0) {
                previewResList.add(storageShelfService.getPreviewResNew(shelfDo, list));
            }
            else {
                previewResList.add(storageShelfService.getPreviewConfig(shelfDo, list));
            }
        }

        Collections.sort(previewResList, new Comparator<PickupPreviewRes>() {
            @Override
            public int compare(PickupPreviewRes o1, PickupPreviewRes o2) {
                if (o1.getShelfSort() == null && o2.getShelfSort() != null) {
                    return 1;
                } else if (o2.getShelfSort() == null && o1.getShelfSort() != null) {
                    return -1;
                } else if (o1.getShelfSort() != null && o2.getShelfSort() != null && !o1.getShelfSort().equals(o2.getShelfSort())) {
                    return o1.getShelfSort() - o2.getShelfSort();
                } else {
                    return 0;
                }
            }
        });

        StockPickupPreviewRes res = new StockPickupPreviewRes();
        res.setList(previewResList);
        res.setDefaultItems(defaultItems);
        return res;
    }


    @Override
    public Map<String, List<OrderOutputDo>> getOrderMapList(List<OrderOutputDo> list, Map<Long, List<OrderOutputProductDo>> productMapList) {
        //分类
        Map<String, List<OrderOutputDo>> mapList = new HashMap<>();
        //先将订单 按照仓库 去分
        Map<Long, List<OrderOutputDo>> map = list.stream().collect(Collectors.groupingBy(OrderOutputDo::getStorageId));
        for (Long storageId : map.keySet()) {
            List<OrderOutputDo> orderList = map.get(storageId);
            StockPickUpRuleDo ruleDo = stockPickUpRuleDao.selectOne(new LambdaQueryWrapper<StockPickUpRuleDo>().eq(StockPickUpRuleDo::getStorageId, storageId).last(" order by id desc limit 1"));
            if (ruleDo == null) {
                ruleDo = stockPickUpRuleService.add(new PickupRuleReq(storageId, 20, 0), null);
            }
            for (OrderOutputDo et : orderList) {
                ProductInfoDo productInfoDo = productInfoDao.selectById(productMapList.get(et.getId()).get(0).getProductId());
                StringBuilder key = new StringBuilder(et.getStorageId() + "");
                if (ruleDo.getTrack() == 1) {
                    //按快递公司分
                    if (key.length() > 0) {
                        key.append("@");
                    }
                    key.append(et.getTrackId());
                }
                if (ruleDo.getCompany() == 1) {
                    //按客户
                    if (key.length() > 0) {
                        key.append("@");
                    }
                    key.append(et.getCompanyId());
                }
                if (ruleDo.getArea() == 1) {
                    //按地区
                    Long stateId = jpRegionService.getStateIdByPostCode(et.getPostCode());
                    if (key.length() > 0) {
                        key.append("@");
                    }
                    key.append(stateId == 9L ? 9 : 0);
                }
                if (ruleDo.getPackageType() == 1) {
                    //包裹类型
                    if (key.length() > 0) {
                        key.append("@");
                    }
                    key.append(productMapList.get(et.getId()).size() > 1 || productMapList.get(et.getId()).get(0).getCount() > 1 ? 2 : 1);// 2 一单多件 1一单一件
                }
                if (ruleDo.getOutType() == 1) {
                    //先进先出 只针对一单一件
                    if (key.length() > 0) {
                        key.append("@");
                    }
                    key.append(productMapList.get(et.getId()).size() > 1 || productMapList.get(et.getId()).get(0).getCount() > 1 ? 2 : productInfoDo.getOutType());//2 一单多件 1 先进先出 0 不是先进先出
                }
                if (ruleDo.getSizeType() == 1) {
                    //大小件 只针对一单一件
                    if (key.length() > 0) {
                        key.append("@");
                    }
                    key.append(productMapList.get(et.getId()).size() > 1 || productMapList.get(et.getId()).get(0).getCount() > 1 ? 2 : productInfoDo.getSizeType());//2 一单多件 1 大件 0 小件
                }
                if (ruleDo.getSku() == 1) {
                    //按sku 只针对一单一件
                    if (key.length() > 0) {
                        key.append("@");
                    }
                    key.append(productMapList.get(et.getId()).size() > 1 || productMapList.get(et.getId()).get(0).getCount() > 1 ? 0 : productInfoDo.getId());//0 一单多件 其他按sku Id
                }
                if (ruleDo.getDefaultRack() == 1) {
                    //按默认库位 只针对一单一件
                }
                mapList.computeIfAbsent(key.toString(), k -> new ArrayList<>()).add(et);
            }
        }
        return mapList;
    }

    /**
     * 定时生成波次
     */
    @Override
    public void generatePickup() {
        //获取符合条件的出库单
        List<OrderOutputDo> orderList = orderOutputDao.getToPickupList();
        if (orderList.size() == 0) {
            return;
        }
        Map<Long, List<OrderOutputDo>> map = orderList.stream().collect(Collectors.groupingBy(OrderOutputDo::getStorageId));
        //波次规则
        List<StockPickUpRuleDo> ruleDoList = stockPickUpRuleDao.selectList(new LambdaQueryWrapper<StockPickUpRuleDo>().ne(StockPickUpRuleDo::getModelType, 0));
        for (StockPickUpRuleDo ruleDo : ruleDoList) {
            if (ruleDo == null || ruleDo.getModelType() == 0) {
                continue;
            }
            List<OrderOutputDo> list = map.get(ruleDo.getStorageId());
            if (list == null || list.size() == 0) {
                continue;
            }

            if (ruleDo.getGenerateType() == 0) {
                Date now = new Date();
                Object value = redisTemplate.opsForValue().get("StockPickupRule_GenerateType_0");
                if (value == null) {
                    if (DateUtils.differentMinByMillisecond(ruleDo.getCreateTime(), now) < ruleDo.getIntervalTime()) {
                        continue;
                    }
                } else {
                    Date date1 = DateUtils.stringFormatToDate(value.toString(), "yyyy-MM-dd HH:mm:ss");
                    if ((now.getTime() - date1.getTime()) / 1000 * 60 < ruleDo.getIntervalTime()) {
                        continue;
                    }
                }

                redisTemplate.opsForValue().set("StockPickupRule_GenerateType_0", DateUtils.dateFormatToString(now, "yyyy-MM-dd HH:mm:ss"), 60L * (ruleDo.getIntervalTime() + 10), TimeUnit.SECONDS);
            } else if (ruleDo.getGenerateType() == 1) {
                if (list.size() < ruleDo.getOrderCount()) {
                   continue;
                }
            } else if (ruleDo.getGenerateType() == 2) {
                //先去看今天有没有 执行过 , 1000L * 60 * 60 * 24
                Object value = redisTemplate.opsForValue().get("StockPickupRule_GenerateType_2_" + ruleDo.getDeadTime() + "_" + DateUtils.dateFormatToString(new Date()));
                if (value != null) {
                    //说明今天生成过了
                    continue;
                }
                String date = DateUtils.dateFormatToString(new Date(), "yyyy-MM-dd") + " " + ruleDo.getDeadTime() + ":00";
                Calendar calendar1 = Calendar.getInstance();
                calendar1.setTime(DateUtils.stringFormatToDate(date, "yyyy-MM-dd HH:mm:ss"));

                Calendar calendar2 = Calendar.getInstance();
                calendar2.setTime(new Date());
                if (calendar1.after(calendar2)) {
                    continue;
                }
                redisTemplate.opsForValue().set("StockPickupRule_GenerateType_2_" + ruleDo.getDeadTime() + "_" + DateUtils.dateFormatToString(new Date()), 1, 60 * 60 * 24, TimeUnit.SECONDS);
            }

            //判断是一单一件还是一单多件
            List<OrderOutputProductDo> productDoList = orderOutputProductDao.selectList(new LambdaQueryWrapper<OrderOutputProductDo>()
                    .in(OrderOutputProductDo::getOrderId, list.stream().map(OrderOutputDo::getId).collect(Collectors.toList())));
            Map<Long, List<OrderOutputProductDo>> productMapList = productDoList.stream().collect(Collectors.groupingBy(OrderOutputProductDo::getOrderId));

            //分类
            Map<String, List<OrderOutputDo>> mapList = this.getOrderMapList(list, productMapList);

            for (String key : mapList.keySet()) {
                List<OrderOutputDo> orderOutputList = mapList.get(key);

                List<PositionAndNumberDTO> positionAndNumberList = new ArrayList<>();
                List<PositionAndNumberDTO> defaultPositionList = new ArrayList<>();
                this.getPositionList(orderOutputList, productMapList, positionAndNumberList, defaultPositionList, ruleDo);

                //一个波次 //如果是一单一件，且选择了默认库位
                //保存到拣货表
                Map<Long, Long> orderPickMap = new HashMap<>();
                if (positionAndNumberList.size() > 0) {
                    this.insertPickup(positionAndNumberList, orderOutputList, ruleDo, key, orderPickMap, 0);
                }
                if (defaultPositionList.size() > 0) {
                    this.insertPickup(defaultPositionList, orderOutputList, ruleDo, key, orderPickMap, 1);
                }
                //出库单/fba出库单关联拣货表id
                for (OrderOutputDo et : orderOutputList) {
                    if (orderPickMap.get(et.getId()) == null) {
                        throw new BizException("定时生成波次单, 出库单未匹配到波次单");
                    }
                    et.setPickUpId(orderPickMap.get(et.getId()));
                    et.setStatus(DicBusinessItemConstant.waitingPickUp);
                    et.setUpdateTime(new Date());
//                    et.setUpdateBy(userId);
                    orderOutputDao.updateById(et);
                }
            }
        }
    }

    @Override
    public SendRes getPositionList(List<OrderOutputDo> orderOutputList, Map<Long, List<OrderOutputProductDo>> productMapList, List<PositionAndNumberDTO> positionAndNumberList, List<PositionAndNumberDTO> defaultPositionList, StockPickUpRuleDo ruleDo) {
        SendRes sendRes = new SendRes();
        StorageDo storageDo = storageDao.selectById(orderOutputList.get(0).getStorageId());
        for (OrderOutputDo et : orderOutputList) {
            Map<String, Integer> countMap = new HashMap<>();
            List<OrderOutputProductDo> productList = productMapList.get(et.getId());
            for (OrderOutputProductDo pt : productList) {
                countMap.merge(pt.getProductId() + "-" + et.getStorageId() + "-" + et.getCompanyId(), pt.getCount(), Integer::sum);
            }
            for (String value : countMap.keySet()) {
                Long productId = Long.parseLong(value.split("-")[0]);
                ProductInfoDo productInfoDo = productInfoDao.selectById(productId);

                Map<String, String> map = new HashMap<>();
                map.put("productId", value.split("-")[0]);
                map.put("storageId", value.split("-")[1]);
                map.put("companyId", value.split("-")[2]);
                if (productInfoDo.getOutType() == 1) {
                    map.put("outType", productInfoDo.getOutType() + "");
                }
                List<PickupStockRackDto> stockRackList;
                //倒序获取库位货存 可做到先进先出
                synchronized (this) {
                    stockRackList = productStockRackDao.getStockRackBySort(map);
                }

                int goodQuantity = countMap.get(value);
                if (stockRackList.size() <= 0 || stockRackList.stream().mapToInt(PickupStockRackDto::getGoodQuantity).sum() < goodQuantity) {
                    sendRes.setCode(500);
                    sendRes.setMsg(StringsUtil.createI18Message(SysConstant.Product_Stock_NotEnough_Order, et.getOrderOutputNumber()));
                    return sendRes;
                }
                for (PickupStockRackDto st : stockRackList) {
                    if (st.getGoodQuantity() <= 0) {
                        continue;
                    }
                    if (ruleDo.getDefaultRack() == 1 && productList.size() == 1 && productList.get(0).getCount() == 1 && st.getRackId() == null) {
                        //有波次规则。且勾选了默认库位，且是一单一件， 且是默认库位
                        goodQuantity = this.getPositionAndNumberDTO(defaultPositionList, st, productInfoDo, storageDo, goodQuantity, et.getId());
                    } else {
                        goodQuantity = this.getPositionAndNumberDTO(positionAndNumberList, st, productInfoDo, storageDo, goodQuantity, et.getId());
                    }
                    if (goodQuantity <= 0) {
                        break;
                    }
                }
//                    countTotalMap.merge(value, countMap.get(value), Integer::sum);
                if (goodQuantity > 0) {
                    sendRes.setCode(500);
                    sendRes.setMsg(StringsUtil.createI18Message(SysConstant.Product_Stock_NotEnough_Order, et.getOrderOutputNumber()));
                    return sendRes ;
                }
            }
        }
        return sendRes;
    }


    public void insertPickup(List<PositionAndNumberDTO> positionAndNumberList, List<OrderOutputDo> orderOutputList, StockPickUpRuleDo ruleDo,  String key,Map<Long, Long> orderPickMap, int defaultRack) {
//        Map<Long, List<PositionAndNumberDTO>> collect = positionAndNumberList.stream().collect(Collectors.groupingBy(PositionAndNumberDTO::getOrderOutputId));
        StockPickUpDo pickUpDo = new StockPickUpDo();
        String pickUpNum = DateFormater.formatMillionSecond(new Date());
        //检查pickNumber是否重复
        int count = dao.selectCount(new QueryWrapper<StockPickUpDo>().eq("pick_up_number", "JH" + pickUpNum));
        if (count > 0) {
            //从第二位开始截取
            long num = Long.parseLong(pickUpNum);
            //重复加一
            pickUpDo.setPickUpNumber("JH" + (num + 1));
        } else {
            pickUpDo.setPickUpNumber("JH" + pickUpNum);
        }

        int track = ruleDo.getTrack();
        int company = ruleDo.getCompany();
        int area = ruleDo.getArea();
        int packageType = ruleDo.getPackageType();
        int outType = ruleDo.getOutType();
        int sizeType = ruleDo.getSizeType();
        int sku = ruleDo.getSku();
        StringBuilder trackName = new StringBuilder();
        StringBuilder otherRule = new StringBuilder();
        for (int i = 0; i < key.split("@").length; i++) {
            if (i == 0) {
                //第一个是仓库
                continue;
            }
            String s = key.split("@")[i];
            if (track == 1) {
                //按快递公司分
                if (trackName.length() > 0) {
                    trackName.append(",");
                }
                trackName.append(dicBusinessItemService.getDicItemValue(Long.parseLong(s)));
                pickUpDo.setTrackId(Long.parseLong(s));
                track = 0;
                continue;
            }
            if (company == 1) {
                //按客户
                CompanyDo companyDo = companyDao.selectById(Long.parseLong(s));
                if (companyDo != null) {
                    if (otherRule.length() > 0) {
                        otherRule.append(",");
                    }
                    otherRule.append(companyDo.getCompanyCode());
                    pickUpDo.setCompanyId(companyDo.getId());
                }
                company = 0;
                continue;
            }
            if (area == 1) {
                //地区
                if (otherRule.length() > 0) {
                    otherRule.append(",");
                }
                if ("9".equals(s)) {
                    //关东
                    otherRule.append("关东地区");
                }
                else {
                    //其他
                    otherRule.append("其他地区");
                }
                area = 0;
                continue;
            }
            if (packageType == 1) {
                //包裹类型 2 一单多件 1一单一件
                if (otherRule.length() > 0) {
                    otherRule.append(",");
                }
                otherRule.append("2".equals(s) ? "一单多件" : "一单一件");
                pickUpDo.setOrderType("2".equals(s) ? 2 : 1);
                packageType = 0;
                continue;
            }
            if (outType == 1) {
                //先进先出 只针对一单一件 1 先进先出 0 不是先进先出
                if (otherRule.length() > 0) {
                    otherRule.append(",");
                }
                otherRule.append("1".equals(s) ? "先进先出" : "非先进先出");
                outType = 0;
                continue;
            }
            if (sizeType == 1) {
                //大小件 只针对一单一件 1 大件 0 小件
                if (otherRule.length() > 0) {
                    otherRule.append(",");
                }
                otherRule.append("1".equals(s) ? "大件" : "小件");
                sizeType = 0;
                continue;
            }
            if (sku == 1) {
                //按sku 只针对一单一件
                if (otherRule.length() > 0) {
                    otherRule.append(",");
                }
                otherRule.append("0".equals(s) ? "不按sku" : "按sku");
                sku = 0;
                continue;
            }
        }
        if (ruleDo.getDefaultRack() == 1) {
            if (otherRule.length() > 0) {
                otherRule.append(",");
            }
            if (defaultRack == 1) {
                otherRule.append("默认库位");
            }
            else {
                otherRule.append("非默认库位");
            }
        }
        pickUpDo.setStatus(0);
        pickUpDo.setRuleId(ruleDo.getId());
        pickUpDo.setType("output");
        pickUpDo.setOtherRule(otherRule.toString());
        pickUpDo.setStorageId(orderOutputList.get(0).getStorageId());
        pickUpDo.setCreateTime(new Date());
        if (pickUpDo.getTrackId() == null) {
            Map<Long, List<PositionAndNumberDTO>> positionMap = positionAndNumberList.stream().collect(Collectors.groupingBy(PositionAndNumberDTO::getOrderOutputId));
            Set<Long> trackId = new HashSet<>();
            for (OrderOutputDo e : orderOutputList) {
                if (positionMap.get(e.getId()) != null) {
                    trackId.add(e.getTrackId());
                }
            }
            if (trackId.size() == 1) {
                pickUpDo.setTrackId(orderOutputList.get(0).getTrackId());
            }
        }
        dao.insert(pickUpDo);

        Map<Long, List<OrderOutputDo>> outputMapList = orderOutputList.stream().collect(Collectors.groupingBy(OrderOutputDo::getId));

        for (PositionAndNumberDTO positionAndNumberDTO : positionAndNumberList) {
            //添加到拣货详情表
            StockPickUpDetailDo pickUpDetailDo = new StockPickUpDetailDo();
            pickUpDetailDo.setPickUpId(pickUpDo.getId());
            pickUpDetailDo.setProductId(positionAndNumberDTO.getProductId());
            pickUpDetailDo.setStockRackId(positionAndNumberDTO.getStockRackId());
            pickUpDetailDo.setNumber(positionAndNumberDTO.getNumber());
            pickUpDetailDo.setOrderOutputId(positionAndNumberDTO.getOrderOutputId());
            stockPickUpDetailDao.insert(pickUpDetailDo);

            orderPickMap.put(positionAndNumberDTO.getOrderOutputId(), pickUpDo.getId());

            OrderOutputDo outputDo = outputMapList.get(positionAndNumberDTO.getOrderOutputId()).get(0);
            ProductStockFlowingDo flowingDo = new ProductStockFlowingDo();

            flowingDo.setNoteNo(outputDo.getOrderOutputNumber());
            flowingDo.setCompanyId(outputDo.getCompanyId());
            flowingDo.setShopId(outputDo.getShopId());
            flowingDo.setTips("出库单拣货,锁定库存");

            ProductStockRackDo racKDo = productStockRackDao.selectById(positionAndNumberDTO.getStockRackId());
            //锁定库存前 判断货位库存量是否足够
            if (positionAndNumberDTO.getNumber() <= racKDo.getGoodQuantity()) {
                racKDo.setGoodQuantity(racKDo.getGoodQuantity() - positionAndNumberDTO.getNumber());
                racKDo.setGoodLockQuantity(racKDo.getGoodLockQuantity() + positionAndNumberDTO.getNumber());
                productStockRackDao.updateById(racKDo);

                flowingDo.setType(pickUpDo.getType());
                flowingDo.setProductId(positionAndNumberDTO.getProductId());
                flowingDo.setStorageId(pickUpDo.getStorageId());
                flowingDo.setGoodQuantity(-positionAndNumberDTO.getNumber());
                flowingDo.setGoodLockingQuantity(positionAndNumberDTO.getNumber());
                flowingDo.setCreateTime(new Date());
                flowingDo.setCreateBy(null);

                flowingDo.setRackId(racKDo.getRackId());
                productStockFlowingDao.insert(flowingDo);
            } else {
                ProductInfoDo productInfoDo = productInfoDao.selectById(positionAndNumberDTO.getProductId());
                if (productInfoDo == null) {
                    throw new BizException(SysConstant.Product_NotExist);
                }
                StoragePositionDo positionDo = storagePositionDao.selectById(racKDo.getRackId());
                throw new BizException(SysConstant.StockPickup_Finish_Error, productInfoDo.getCommoditySku(), positionDo.getPositionName(), positionAndNumberDTO.getNumber() - racKDo.getGoodQuantity());
//                throw new BizException("sku:" + productInfoDo.getCommoditySku() + " 库位:" + positionDo.getPositionName() + "库存不足，缺少：" + (positionAndNumberDTO.getNumber() - racKDo.getGoodQuantity()) + "件");
            }
        }
    }


    //波次认领
    @Override
    public void claimPickup(Long id, Long userId) {
        StockPickUpDo pickUpDo = dao.selectById(id);
        if (pickUpDo == null) {
            throw new BizException(SysConstant.StockPickup_NotExist);
        }
        if (pickUpDo.getStatus() == 1) {
            //已完成拣货
            throw new BizException(SysConstant.StockPickup_HadPicked);
        }
        if (pickUpDo.getClaimBy() != null) {
            throw new BizException(SysConstant.StockPickup_HadClaim);
        }
        pickUpDo.setClaimBy(userId);
        pickUpDo.setClaimTime(new Date());
        dao.updateById(pickUpDo);
    }


    @Override
    public List<Map<String, Object>> getClaimUserId() {
        List<UserDo> list = userDao.selectList(new LambdaQueryWrapper<UserDo>().eq(UserDo::getUserType, 2));

        List<Map<String, Object>> mapList = new ArrayList<>();
        for (UserDo userDo : list) {
            Map<String, Object> result = new HashMap<>();
            result.put("id", userDo.getId());
            result.put("value", userDo.getUserName());
            mapList.add(result);
        }
        return mapList;
    }
}
